﻿using System.Security.Cryptography;

namespace FrameworkCore.Modules;

/// <summary>
/// 表示加密随机数生成器的类实现
/// </summary>
public partial class SecureRandomNumberGenerator : RandomNumberGenerator
{
    #region Field

    protected bool _disposed;
    protected readonly RandomNumberGenerator _rng;

    #endregion

    #region Ctor

    public SecureRandomNumberGenerator()
    {
        _rng = Create();
    }

    #endregion

    #region Methods

    /// <summary>
    /// 返回一个非负随机整数
    /// </summary>
    public int Next()
    {
        var data = new byte[sizeof(int)];
        _rng.GetBytes(data);
        return BitConverter.ToInt32(data, 0) & int.MaxValue - 1;
    }

    /// <summary>
    /// 返回一个小于最大值的非负随机整数
    /// </summary>
    public int Next(int maxValue)
    {
        return Next(0, maxValue);
    }

    /// <summary>
    /// 返回一个指定范围内的随机整数
    /// </summary>
    public int Next(int minValue, int maxValue)
    {
        ArgumentOutOfRangeException.ThrowIfGreaterThan(minValue, maxValue);
        return (int)Math.Floor(minValue + ((double)maxValue - minValue) * NextDouble());
    }

    /// <summary>
    /// 返回一个大于或等于 0.0 且小于 1.0 的随机浮点数
    /// </summary>
    public double NextDouble()
    {
        var data = new byte[sizeof(uint)];
        _rng.GetBytes(data);
        var randUint = BitConverter.ToUInt32(data, 0);
        return randUint / (uint.MaxValue + 1.0);
    }

    /// <summary>
    /// 用随机数填充指定的字节数组
    /// </summary>
    public override void GetBytes(byte[] data)
    {
        _rng.GetBytes(data);
    }

    /// <summary>
    /// 用随机数填充指定的非零字节数组
    /// </summary>
    public override void GetNonZeroBytes(byte[] data)
    {
        _rng.GetNonZeroBytes(data);
    }

    /// <summary>
    /// 释放安全随机数
    /// </summary>
    public new void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // 实现 Dispose 模式的受保护方法。
    protected override void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            _rng?.Dispose();
        }

        _disposed = true;
    }

    #endregion
}
